<?php

namespace backend\modules\tool\models;

use backend\modules\peace\models\PeaceReportTypeBack;
use backend\modules\tool\helpers\FileHelper;
use backend\modules\tool\helpers\StringHelper;
use common\functions\StringUtil;
use Yii;

/**
 * This is the model class for table "{{%fill_for_template}}".
 *
 * @property int $id
 * @property string $template 模版JSON
 */
class FillForTemplate extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public  $template_key;
    public $template_rules;
    protected $template_path="";
    const template_path=[
        "model"=>"model.php.template",
        "module"=>"Module.php.template",
        "controller"=>"controller.php.template"
    ];
    const viewspath="views";
    const default_views_path="views1";
    public $basepath;
    public static function tableName()
    {
        return '{{%fill_for_template}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [[ 'template','key',"primary_key","title"], 'required'],
            [['id'], 'integer'],
            [['template'], 'string'],
            [['id'], 'unique'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'template' => '模版JSON',
            'key'=>"模版的键唯一键",
            'p_key'=>"模版的父键",
            "primary_key"=>"生成模板的主键名,需要在fileds里面写明",
            "title"=>"模板主题"
        ];
    }
    public function __construct($config = [])
    {
        parent::__construct($config);
        $this->template_path=dirname(dirname(__FILE__))."/template/";
        $this->basepath=dirname(Yii::$app->basePath).'/';
    }
    public function afterFind()
    {
        parent::afterFind(); // TODO: Change the autogenerated stub
        if(json_decode($this->template,true)['is_unique']){
            $this->template_path=$this->template_path."/unique/";
        }
    }

    /**
     */
    protected function CompileTemplateRules(){
        if(!empty($this->template)){
            $rules=[];
            $attribute=[];
            $propertys=[];
            $rules["safe"]=[];
            $template=json_decode($this->template,true);
            foreach ($template['fileds'] as $filed){
                $attribute[$filed['name']]=$filed['comment'];//生成yii的attribute;
                $propertys[]=["type"=>$filed['type'],'name'=>$filed['name']];
                if(empty($filed['rules'])){
                    $rules['safe'][]=$filed['name'];
                }
                else{
                    foreach ($filed['rules'] as $rule=>$params){
                        $rule_key=$rule."___".json_encode($params);
                        if(!array_key_exists($rule_key,$rules)){
                            $rules[$rule_key]=[];
                        }
                        $rules[$rule_key][]=$filed['name'];
                    }
                }
            }
            $real_rules=[];
            foreach ($rules as $key=>$value){
                $params=explode("___",$key);
                $real_rules[]=["rule"=>$params[0],"params"=>!empty($params[1])?json_decode($params[1],true):'',"fileds"=>$value];
            }
            return [
                'rule'=>$real_rules,
                'attribute'=>$attribute,
                'propertys'=>$propertys
            ];
        }else{
            throw new \Exception("Failed to get the template rules");
        }
    }

    /**
     * 编译模板需要的核心参数
     * @return array
     * @throws \Exception
     */
    protected function CompileModelString()
    {
        $tempalte_rules = $this->CompileTemplateRules();
        //start compile template model propertys
        $property_string = "/**";
        foreach ($tempalte_rules['propertys'] as $property) {
            $property_string .= "*@property " . $property['type'] . " $" . $property['name'] . PHP_EOL;
        }
        $property_string .= " */" . PHP_EOL;
        //end compile
        //start compile template rules
        $rules_array = [];
        foreach ($tempalte_rules['rule'] as $item) {
            if (empty($item['fileds'])) {
                continue;
            }
            $rules_item = "[";
            $rules_item .= '[' . self::implode($item['fileds']) . '],';
            $rules_item .= "'" . $item['rule'] . "'";
            if (!empty($params_string = $this->CompileRulesParams($item['params']))) {
                $rules_item .= "," . $params_string;
            }
            $rules_item .= "]";
            $rules_array[] = $rules_item;
        }
        $rules_string = implode("," . PHP_EOL, $rules_array);
        //end compile template rules
        //start compile template attribute
        $attribute_string = "";
        $fileds_string = "";
        foreach ($tempalte_rules['attribute'] as $key => $value) {
            $attribute_string .= "'" . $key . "'=>'" . $value . "'," . PHP_EOL;
            $fileds_string .= "public $" . $key . ";" . PHP_EOL;
        }
        //end compile template attribute
        return [
            'rule' => $this->AddPHPEOF($rules_string),
            'propertys' => $this->AddPHPEOF($property_string, 0),
            'attribute' => $this->AddPHPEOF($attribute_string),
            'fileds' => $this->AddPHPEOF($fileds_string, 4)
        ];
    }
    public function CompileCRUDTemplate(array $params){
    }
    public function CompileModel($namespace,$modelname,$controllername){
        $this->RegisterModules($namespace);
        $params=$this->CompileModelString();
        $params['namespace']=$namespace;
        $params['class']=$modelname;
        $params['primary_key']=$this->primary_key;
        $params['template_key']=$this->key;
        $params['controllername']=$controllername;
        $params['is_unique']=json_decode($this->template,true)['is_unique']?'true':"false";
        $modeltemplate=self::CompileTemplate($this->template_path.self::template_path['model'],$params);
        $module_path=$this->basepath.$namespace."\\";
        $path=$module_path."models/";
        FileHelper::mkdir($path);
        if(!is_file($module_path."Module.php")){
            file_put_contents($module_path."Module.php",self::CompileTemplate($this->template_path.self::template_path['module'],$params));
        }
        if(!is_dir($path)){
            FileHelper::mkdir($path);
        }
        if(!is_file($path.$modelname.".php")){
            file_put_contents($path.$modelname.".php",$modeltemplate);
        }
        $controller_path=$module_path."controllers\\";
        if(!is_dir($controller_path)){
            FileHelper::mkdir($controller_path);
        }
        $params['class']=$controllername;
        $params['modelname']=$modelname;
        $controller_template_string=self::CompileTemplate($this->template_path.self::template_path['controller'],$params);
        file_put_contents($controller_path.$controllername.".php",$controller_template_string);
        $template_params=json_decode($this->template,true);
        $params['title']=$this->title;
        $this->CompileTemplateView(self::default_views_path,$module_path,$params);
    }

    /**
     * 编译验证规则里面的参数
     * @param $params
     * @return false|string|null
     *
     */
    protected function CompileRulesParams($params){
        if(empty($params)){
            return null;
        }
        $params_string="";
        foreach ($params as $key=>$value){
            $params_string.="'".$key."'=>'".$value."',";
        }
        return substr($params_string,0,strlen($params_string)-1);
    }

    /**
     * 生成模板文件
     * @param $template_path
     * @param array $params
     * @return false|string|string[]
     * @throws \Exception
     */
    protected static function CompileTemplate($template_path,array $params){
        if(!is_file($template_path)){
            throw new \Exception("Tempalte file not find");
        }
        $template_string=file_get_contents($template_path);
        foreach ($params as $key=>$value){
            $template_string=str_replace("{{{$key}}}",$value,$template_string);
        }
        return $template_string;
    }
    protected static function implode(array $arr,$deplo=","){
        $str="";
        foreach ($arr as $item){
            $str.="'".$item."'$deplo";
        }
        return self::RemoveLast($str);
    }
    protected static function RemoveLast($str,$len=1){
        return substr($str,0,strlen($str)-$len);
    }
    protected function AddPHPEOF($str,$num=12){
        $result="";
        $arr=explode(PHP_EOL,$str);
        foreach ($arr as $index=>$value){
            if($index==count($arr)-1){
                $result.=str_repeat(" ",$num).$value;
                continue;
            }
            $result.=str_repeat(" ",$num).$value.PHP_EOL;
        }
        return $result;
    }
    protected function CompileTemplateView($path,$modulepath,array $params){
        $fileds=array_keys($this->CompileTemplateRules()['attribute']);
        $template_path=FileHelper::FileWalk($this->template_path.$path);
        $fileds_string="";
        $fileds_list_string="";
        foreach ($fileds as $filed){
            $template_model_fileds=' <?= $form->field($model, \'{{filed}}\')->textInput() ?>';
            $fileds_string.=str_replace("{{filed}}","$filed",$template_model_fileds).PHP_EOL;
            $fileds_list_string.="'".$filed."',".PHP_EOL;
        }
        $params['fileds_model']=self::RemoveLast(self::AddPHPEOF($fileds_string,3),2);
        $params['fileds_list_string']=self::RemoveLast(self::AddPHPEOF($fileds_list_string),2);
//        $model_info=preg_split("/[A-Z]/",lcfirst($params['modelname']));
        $controller_name=str_replace("Controller","",$params['controllername']);
        $view_path=StringHelper::toUnderScore($controller_name,"-");
//        foreach ($model_info as $item){
//            $view_path.=strtolower($item)."-";
//        }
        $view_path=self::RemoveLast($view_path,1);
        $view_path=$modulepath."views/".$view_path."/";
        foreach ($template_path as $item){
            FileHelper::mkdir($view_path);
            $create_path=$view_path.self::GetFileName($item).".php";
            $template_str=self::CompileTemplate($item,$params);
            file_put_contents($create_path,$template_str);
        }
    }
    protected static function GetFileName($path){
        $name_info=explode("/",$path);
        $name=$name_info[count($name_info)-1];
        return explode('.',$name)[0];
    }
    protected function RegisterModules($modulename){
        $modules_path=Yii::$app->basePath."\config\modules.php";
        if(is_file($modules_path)) {
            try {
                $modules_params = require $modules_path;
            }
            catch (\Throwable $e){
                $modules_params=[];
            }
        }else{
            $modules_params=[];
        }
        $modules_params=array_values($modules_params);
        $params=[];
        foreach ($modules_params as $param){

            $params[]=str_replace("\Module","",array_values($param)[0]);
        }
        $modules_params=$params;
        $modules_params[]=$modulename;
        $modules_params=array_unique($modules_params);
        $template="";
        foreach ($modules_params as $item){
            $module_name=explode("\\",$item);
            $template.="'".$module_name[count($module_name)-1]."'=>[".
                "'class'=>".$modulename."\Module::class],".PHP_EOL;
        }
        $template=self::RemoveLast($template,3);
        $template="<?php
return [".
            $template
            ."];";
        file_put_contents($modules_path,$template);
    }
    public static function RegisterModule($config){
        $path=dirname(dirname($_SERVER['SCRIPT_FILENAME']));
        $modules_path=$path."\config\modules.php";
        if(!is_file($modules_path)){
            return $config;
        }else{
            try {
                $modules=require_once $modules_path;
                $config['modules']=array_merge($config['modules'],$modules);
                return $config;
            }
            catch (\Throwable $exception){
                return $config;
            }
        }
    }
}
